package com.suse.service.community.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.suse.common.util.date.DateFormatter;
import com.suse.common.util.date.DateUtil;
import com.suse.service.community.service.StatisticsService;
import com.suse.service.community.util.RedisUtil;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 统计业务实现类
 * </p>
 *
 * @author 辜玉彬
 * @since 2022-09-06 18:34
 */
@Service
public class StatisticsServiceImpl implements StatisticsService {

    @Resource
    private RedisTemplate<Object, Object> redisTemplate;

    private final DateFormatter df = DateFormatter.ofPattern("yyyyMMdd");

    @Override
    public void logUV(String ip) {
        String date = df.format(DateUtil.now());
        String uvKey = RedisUtil.getUVKey(date);
        redisTemplate.opsForHyperLogLog().add(uvKey,ip);
    }

    @Override
    public long getUV(Date start, Date end) {
        // 获取指定日期范围内各日期对应的 UV（unique visitor） Redis Key 列表
        List<String> uvKeyList = new ArrayList<>();
        DateUtil.datesUntil(start,end).forEach((date -> {
            String uvKey = RedisUtil.getUVKey(df.format(date));
            uvKeyList.add(uvKey);
        }));
        // 聚合数据
        String scopeUvKey = RedisUtil.getUVKey(df.format(start), df.format(end));
        redisTemplate.opsForHyperLogLog().union(scopeUvKey,uvKeyList.toArray());
        return redisTemplate.opsForHyperLogLog().size(scopeUvKey);
    }

    @Override
    public void logDVU(int userId) {
        String dvuKey = RedisUtil.getDVUKey(df.format(DateUtil.now()));
        redisTemplate.opsForValue().setBit(dvuKey,userId,true);
    }

    @Override
    public long getDVU(Date start, Date end) {
        // 获取指定日期范围内各日期对应的 DVU（Daily Active User） Redis Key 列表
        List<byte[]> dvuKeyList = new ArrayList<>();
        DateUtil.datesUntil(start,end).forEach((date -> {
            String dvuKey = RedisUtil.getDVUKey(df.format(date));
            dvuKeyList.add(dvuKey.getBytes());
        }));
        // 聚合数据
        Long count = redisTemplate.execute((RedisCallback<Long>) connection -> {
            String scopeDvuKey = RedisUtil.getDVUKey(df.format(start), df.format(end));
            connection.bitOp(RedisStringCommands.BitOperation.OR, scopeDvuKey.getBytes(), dvuKeyList.toArray(new byte[0][0]));
            return connection.bitCount(scopeDvuKey.getBytes());
        });
        if (ObjectUtil.isNull(count)) {
            return 0;
        }
        return count;
    }

}
